﻿// 2023/3/20: 首个版本
// 2023/9/25: 改为直接输入Icon对象

using System;
using System.Collections.Generic;
using System.Linq;
using ASEva;
using ASEva.Samples;
using ASEva.UIEto;
using Eto.Forms;
using Eto.Drawing;

namespace CommonSource
{
    class SignalChooser : DialogPanel
    {
        public SignalChooser(String originSignalID, double? originSignalScale, String unit, Icon icon = null)
        {
            current = originSignalID;
            currentScale = originSignalScale;

            Icon = icon;
            Title = chinese ? "信号选择" : "Select Signal";
            SetFixMode(440, 570, true);

            var mainLayout = this.SetContentAsColumnLayout();
            searchBox = mainLayout.AddControl(new SearchBox()) as SearchBox;
            treeView = mainLayout.AddControl(new SimpleTreeView(), true) as SimpleTreeView;

            TextBox textScale = null;
            if (currentScale != null)
            {
                var unitLayout = mainLayout.AddRowLayout();
                unitLayout.AddLabel(chinese ? "数值 x" : "Value x");
                textScale = unitLayout.AddControl(new TextBox{ Text = currentScale.Value.ToString(), TextColor = Colors.Green }, true) as TextBox;
                if (!String.IsNullOrEmpty(unit)) unitLayout.AddLabel(unit);
            }

            Button buttonDelete = null;
            var buttonLayout = mainLayout.AddRowLayout();
            if (current != null) buttonDelete = buttonLayout.AddButton(chinese ? "删除" : "Delete", false, 100);
            buttonLayout.AddSpace();
            var buttonSelect = buttonLayout.AddButton(chinese ? "确认" : "OK", false, 100);
            buttonSelect.Enabled = current != null;

            noAvailables = !rebuildTreeView(Agency.GetSignalTree(), "", true);
            if (noAvailables)
            {
                searchBox.Enabled = false;
                buttonSelect.Enabled = false;
                addNoAvailables();
            }

            searchBox.TextChanged += delegate
            {
                noAvailables = !rebuildTreeView(Agency.GetSignalTree(), searchBox.Text.ToLower(), false);
                if (noAvailables)
                {
                    buttonSelect.Enabled = false;
                    addNoAvailables();
                }
            };

            if (buttonDelete != null)
            {
                buttonDelete.Click += delegate
                {
                    Result = ResultType.Delete;
                    Close();
                };
            }

            buttonSelect.Click += delegate
            {
                Result = ResultType.Select;
                Close();
            };

            treeView.SelectedItemChanged += delegate
            {
                if (noAvailables) return;

                var key = treeView.GetSelectedKey();
                bool isMultiplexedEntry = key is String;

                String currentUpdate = null;
                if (key is SignalTreeNode)
                {
                    var nodeType = (key as SignalTreeNode).Type;
                    if ((int)nodeType >= (int)SignalTreeNodeType.GeneralSignal) currentUpdate = (key as SignalTreeNode).ID;
                }

                if (!isMultiplexedEntry) current = currentUpdate;

                buttonSelect.Enabled = !isMultiplexedEntry && current != null;
            };

            treeView.SelectedItemActivated += delegate
            {
                if (buttonSelect.Enabled)
                {
                    Result = ResultType.Select;
                    Close();
                }
                else
                {
                    var key = treeView.GetSelectedKey();
                    if (key != null && key is String) searchBox.Text = (key as String) + ".all";
                }
            };

            if (textScale != null)
            {
                textScale.TextChanged += delegate
                {
                    bool scaleOK = true;
                    try
                    {
                        if (textScale.Text.Length == 0) scaleOK = false;
                        else
                        {
                            var val = Convert.ToDouble(textScale.Text);
                            if (val == 0) scaleOK = false;
                            else currentScale = val;
                        }
                    }
                    catch (Exception) { scaleOK = false; }
                    textScale.TextColor = scaleOK ? Colors.Green : Colors.Red;
                    buttonSelect.Enabled = scaleOK && current != null;
                };

                textScale.LostFocus += delegate
                {
                    textScale.Text = currentScale == null ? "1.0" : currentScale.Value.ToString();
                    textScale.TextColor = Colors.Green;
                };

                textScale.KeyDown += (o, e) =>
                {
                    if (e.Key == Keys.Enter && buttonSelect.Enabled)
                    {
                        Result = ResultType.Select;
                        Close();
                    }
                };
            }
        }

        public enum ResultType
        {
            Cancel = 0,
            Select = 1,
            Delete = 2,
        }

        public ResultType Result { get; set; }

        public SignalConfig SelectedSignal
        {
            get
            {
                return new SignalConfig()
                {
                    SignalID = current == null ? null : current.Clone() as String,
                    Scale = currentScale == null ? null : (double?)currentScale.Value,
                };
            }
        }

        private bool rebuildTreeView(SignalTreeNode[] tops, String key, bool init)
        {
            var topNodes = new List<SimpleTreeNode>();
            var itemAdded = false;
            bool keyValid = key.Length >= 2;
            object keyToSelect = null;

            foreach (var top in tops)
            {
                var topMatch = keyValid && (top.ID.ToLower().Contains(key) || top.Name.ToLower().Contains(key));

                var topNode = new SimpleTreeNode{ Key = top, Text = top.Name };
                var shouldAddTopNode = !keyValid || topMatch;

                foreach (var middle in top.Children)
                {
                    var middleMatch = keyValid && (middle.ID.ToLower().Contains(key) || middle.Name.ToLower().Contains(key));
                    var bottomAllMatch = keyValid && (key == middle.ID.ToLower() + ".all");

                    var middleNode = new SimpleTreeNode{ Key = middle, Text = middle.Name };
                    bool shouldAddMiddleNode = !keyValid || topMatch || middleMatch;

                    String multiplexedTarget = null;
                    foreach (var bottom in middle.Children)
                    {
                        var bottomMatch = keyValid && (bottom.ID.ToLower().Contains(key) || bottom.Name.ToLower().Contains(key));

                        SimpleTreeNode bottomNode = null;
                        if (bottom.Type == SignalTreeNodeType.MultiplexedBusSignal)
                        {
                            var isCurrent = current != null && bottom.ID == current;
                            if (bottomAllMatch)
                            {
                                bottomNode = new SimpleTreeNode{ Key = bottom, Text = bottom.Name };
                                if (isCurrent)
                                {
                                    bottomNode.TextColor = Colors.Green;
                                    keyToSelect = bottomNode.Key;
                                }
                                else bottomNode.TextColor = Colors.Blue;
                            }
                            else
                            {
                                if (init && isCurrent)
                                {
                                    var searchKey = middle.ID.ToLower() + ".all";
                                    searchBox.Text = searchKey;
                                    return rebuildTreeView(tops, searchKey, false);
                                }
                                if (shouldAddMiddleNode) multiplexedTarget = middle.ID;
                            }
                        }
                        else
                        {
                            var shouldAddBottomNode = !keyValid || topMatch || middleMatch || bottomMatch || bottomAllMatch;
                            if (shouldAddBottomNode)
                            {
                                bottomNode = new SimpleTreeNode{ Key = bottom, Text = bottom.Name };
                                if (current != null && bottom.ID == current)
                                {
                                    bottomNode.TextColor = Colors.Green;
                                    keyToSelect = bottomNode.Key;
                                }
                                else bottomNode.TextColor = Colors.Blue;
                            }
                        }

                        if (bottomNode != null)
                        {
                            middleNode.ChildNodes.Add(bottomNode);
                            shouldAddMiddleNode = true;
                        }
                    }

                    if (multiplexedTarget != null)
                    {
                        var bottomNode = new SimpleTreeNode{ Key = multiplexedTarget, Text = chinese ? "多路复用信号..." : "Multiplexed signals ..." };
                        middleNode.ChildNodes.Add(bottomNode);
                        shouldAddMiddleNode = true;
                    }

                    if (shouldAddMiddleNode)
                    {
                        if (keyValid) middleNode.ChildNodesExpanded = true;
                        topNode.ChildNodes.Add(middleNode);
                        shouldAddTopNode = true;
                    }
                }

                if (shouldAddTopNode)
                {
                    if (keyValid) topNode.ChildNodesExpanded = true;
                    topNodes.Add(topNode);
                    itemAdded = true;
                }
            }

            treeView.SetModel(topNodes.ToArray(), true);
            if (keyToSelect != null) treeView.SelectItem(keyToSelect);

            return itemAdded;
        }

        private void addNoAvailables()
        {
            var topNode = new SimpleTreeNode{ Key = new object(), Text = chinese ? "(无可用)" : "(No availables)" };
            treeView.SetModel(new SimpleTreeNode[]{ topNode }, false);
        }

        private String current;
        private double? currentScale;
        private bool noAvailables;
        private SimpleTreeView treeView;
        private SearchBox searchBox;

        private bool chinese = Agency.GetAppLanguage() == "ch";
    }
}
